package com.ywy.service.impl;

import com.ywy.dao.CommentDao;
import com.ywy.dao.ResDao;
import com.ywy.dao.UserDownloadDao;
import com.ywy.entity.Res;
import com.ywy.lucene.ResIndex;
import com.ywy.service.ResService;
import com.ywy.utils.RedisUtil;
import com.ywy.utils.StringUtil;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;

/**
 * 资源Service实现类
 *
 * @author ywy
 * @date 2022/8/18 18:43
 */
@Transactional
@Service
public class ResServiceImpl implements ResService {
    @Resource
    private ResDao resDao;
    @Resource
    private UserDownloadDao userDownloadDao;
    @Resource
    private CommentDao commentDao;
    @Resource
    private ResIndex resIndex;
    @Resource
    private RedisUtil<Res> redisUtil;

    @Override
    public List<Res> list(Res res, Integer pageNo, Integer pageSize) {
        Pageable pageable = new PageRequest(pageNo - 1, pageSize, Sort.Direction.DESC, "publishDate");
        Page<Res> pageRes = resDao.findAll(createSpecification(res), pageable);
        return pageRes.getContent();
    }

    @Override
    public List<Res> listFromCache(Res res, Integer pageNo, Integer pageSize) {
        List<Res> resList;
        String hKey = "hotResList_type_" + res.getResType().getId();
        // 缓存中存在数据则直接读取缓存，否则读取数据库并保存到缓存中
        if (redisUtil.hasKey(hKey)) {
            resList = redisUtil.lGet(hKey, 0, -1);
        } else {
            Pageable pageable = new PageRequest(pageNo - 1, pageSize, Sort.Direction.DESC, "publishDate");
            Page<Res> pageRes = resDao.findAll(createSpecification(res), pageable);
            resList = pageRes.getContent();
            if (!resList.isEmpty()) {
                redisUtil.lSet(hKey, resList, 60 * 60);
            }
        }
        return resList;
    }

    @Override
    public long getTotal(Res res) {
        return resDao.count(createSpecification(res));
    }

    @Override
    public Res getById(Integer id) {
        return resDao.findOne(id);
    }

    @Override
    public Res getByIdFromCache(Integer id) {
        Res res;
        String key = "res_" + id;
        // 缓存中存在数据则直接读取缓存，否则读取数据库并保存到缓存中
        if (redisUtil.hasKey(key)) {
            res = redisUtil.get(key);
        } else {
            res = resDao.findOne(id);
            redisUtil.set(key, res, 60 * 60);
        }
        return res;
    }

    @Override
    public Res save(Res res) {
        if (res.getCheckStatus() == 2) {
            // 更新lucene索引
            resIndex.updateIndex(res);
        }
        return resDao.save(res);
    }

    @Override
    public void delete(Integer id) {
        // 删除用户下载记录
        userDownloadDao.deleteByResId(id);
        // 删除评论信息
        commentDao.deleteByResId(id);
        // 删除资源
        resDao.delete(id);
        // 删除lucene索引
        resIndex.deleteIndex(String.valueOf(id));
    }

    @Override
    public boolean genAllIndex() {
        List<Res> resList = resDao.findAll();
        for (Res res : resList) {
            if (!resIndex.addIndex(res)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public int invalid(Integer id) {
        return resDao.invalid(id);
    }

    private Specification createSpecification(Res res) {
        return (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if (res != null) {
                if (res.getName() != null) {
                    list.add(criteriaBuilder.like(root.get("name"), "%" + res.getName().trim() + "%"));
                }
                if (res.getCheckStatus() != null) {
                    list.add(criteriaBuilder.equal(root.get("checkStatus"), res.getCheckStatus()));
                }
                if (res.getResType() != null && res.getResType().getId() != null) {
                    list.add(criteriaBuilder.equal(root.get("resType").get("id"), res.getResType().getId()));
                }
                if (res.isHot()) {
                    list.add(criteriaBuilder.equal(root.get("isHot"), 1));
                }
                if (!res.isUseful()) {
                    list.add(criteriaBuilder.equal(root.get("isUseful"), false));
                }
                if (res.getUser() != null && res.getUser().getId() != null) {
                    list.add(criteriaBuilder.equal(root.get("user").get("id"), res.getUser().getId()));
                }
                if (res.getUser() != null && StringUtil.isNotEmpty(res.getUser().getUsername())) {
                    list.add(criteriaBuilder.like(root.get("user").get("username"), "%" + res.getUser().getUsername() + "%"));
                }
            }
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };
    }
}
